import pickle
import random

import numpy as np
import os
from utils.Excel_utils import xw_toExcel


def load_pickle_data(file_path, workSheetName, num=10000):
    # 读取文件
    with open(file_path, 'rb') as f:
        data = pickle.load(f)
    basename = os.path.basename(file_path).split('.')[0]
    title = list(data.keys())
    title = [*title, "温度(摄氏度)", "相对湿度(%)", "风速(m/s)", "每小时降水量(mm)",
             "风险等级(标注项)"]
    _data = []
    values_selectable = {}
    values_dir_adopted = {}
    values_with_no = {}
    id = 0
    count = 0
    wind_speed = generate_wind_speed(num)
    temperatur = generate_temperature(num)
    humidity = generate_humidity(num)
    precipitation = generate_precipitation(num)
    # 数据类型分类
    for col, value in data.items():
        if '无' in value:
            fill_value = [value[0]]
            retention_value = value[1]
            value = [*(fill_value * len(retention_value)), *retention_value]
            # 打乱数据
            values_with_no[col] = value
        elif len(value) > 50:
            values_dir_adopted[col] = value
        else:
            values_selectable[col] = value
    # 分类标签的分类类别
    flattened_list = [value for value in values_selectable.values()]
    # 直接采用的标签的值
    dir_adopted_list = [value for value in values_dir_adopted.values()]
    dir_adopted_list[0] = generate_unique_codes(dir_adopted_list[0], num)
    dir_adopted_list[1] = expand_list_uniformly_no_shuffle(dir_adopted_list[1], num)
    dir_adopted_list[2] = expand_list_uniformly_no_shuffle(dir_adopted_list[2], num)
    # 标签值带无的值
    with_no_list = [value for value in values_with_no.values()]
    with_no_list = fill_list(with_no_list, num)
    with_no_list = [expand_list_uniformly(value, num) for value in with_no_list]

    # 对多选择值进行循环获取更多得选择可能
    while count != num:
        if count == num:
            break
        _data.append({
            '计划编号': dir_adopted_list[0][id],
            '作业性质': random.choice(flattened_list[0]),
            '专业类型': random.choice(flattened_list[1]),
            '作业内容': dir_adopted_list[1][id],
            '是否停电': random.choice(flattened_list[2]),
            '开始时间点': random.choice(flattened_list[3]),
            '电网类型': random.choice(flattened_list[4]),
            '专业': random.choice(flattened_list[5]),
            '公告牌要求': with_no_list[0][id],
            '施工设备要求': with_no_list[1][id],
            '施工接地线要求': with_no_list[2][id],
            '施工方法要求': with_no_list[3][id],
            '施工额外要求': with_no_list[4][id],
            '施工人员要求': with_no_list[5][id],
            '电力线路设备': with_no_list[6][id],
            '现场安全要求': with_no_list[7][id],
            '是否有邻近设备': random.choice(flattened_list[6]),
            '邻近设备补充': with_no_list[8][id],
            '其他注意事项': with_no_list[9][id],
            '额外作业危险': with_no_list[10][id],
            '停电拉开开关': with_no_list[11][id],
            '停电开关接地线': with_no_list[12][id],
            '现场电力设备': with_no_list[13][id],
            '停电范围': with_no_list[14][id],
            '带电线路设备': with_no_list[15][id],
            '运行人员联系要求': with_no_list[16][id],
            '安全注意事项': with_no_list[17][id],
            '安全注意事项补充': with_no_list[18][id],
            '二次设备回路': with_no_list[19][id],
            '交叉跨越': with_no_list[20][id],
            '涉及地下管线': with_no_list[21][id],
            '现场作业环境': with_no_list[22][id],
            '现场作业环境补充': with_no_list[23][id],
            '电压(V)': random.choice(flattened_list[7]),
            '是否办票': random.choice(flattened_list[8]),
            '需要视频监控': random.choice(flattened_list[9]),
            '作业人数': random.choice(flattened_list[10]),
            '累计作业时长(小时)': dir_adopted_list[2][id],
            '温度(摄氏度)': temperatur[id],
            '相对湿度(%)': humidity[id],
            '风速(m/s)': wind_speed[id],
            '每小时降水量(mm)': precipitation[id],
            '风险等级(标注项)': '需标注',
        })
        count += 1
        id += 1
    xw_toExcel(_data, f'example_dispose{basename}.xlsx', title, workSheetName)


def count_combination(data: dict[list]):
    """
    对种类标签进行组合
    :param data:分类数据
    :return:组合数量
    """
    num_classifications = [len(value) for value in data.values()]
    result = 1
    for number in num_classifications:
        result *= number
    return result


def fill_list(data: list, count: int = 10000):
    """
    为二维列表中一维的空列表进行"无"字填充
    :param data:二位列表
    :param count:填充"无"的个数
    :return:填充后的列表
    """
    for i in range(len(data)):
        if not data[i]:
            data[i] = ['无'] * count
    return data


def generate_unique_codes(existing_codes, target_length=10000):
    """
    生成唯一的代码列表，格式与现有代码相似，且保证后缀数字不重复。
    :param existing_codes: list of str, 现有的代码列表。
    :param target_length: int, 目标列表长度，默认为10000。
    :return: list of str, 扩充后的代码列表。
    """
    code_prefix = "SCWH05012412"
    existing_numbers = set(int(code[16:]) for code in existing_codes)

    while len(existing_codes) < target_length:
        suffix = random.randint(1000000, 9999999)  # 随机生成7位数的后缀
        new_code = f"{code_prefix}{suffix}"

        if suffix not in existing_numbers:
            existing_codes.append(new_code)
            existing_numbers.add(suffix)
    return existing_codes


def expand_list_uniformly(originallist, target_length):
    """
    将一个原始列表扩展到指定的长度，添加的值均匀地从原始列表中选取。
    原始列表中的值保持不变。

    :param originallist: 初始列表，可以是任意长度
    :param target_length: 目标长度，扩展后的列表长度
    :return: 扩展后的列表
    """
    original_length = len(originallist)
    if original_length == 0:
        raise ValueError("原始列表不能为空")
    if target_length < original_length:
        raise ValueError("目标长度不能小于原始列表的长度")

    # 计算需要添加的元素总数
    total_to_add = target_length - original_length

    # 计算每个元素需要添加的次数
    repeat_count = total_to_add // original_length
    extra_count = total_to_add % original_length

    # 创建新列表，首先包含原始列表的所有元素
    expanded_list = originallist.copy()

    # 添加均匀分布的元素
    for i in range(original_length):
        # 添加重复的值
        expanded_list.extend([originallist[i]] * repeat_count)
        # 如果需要，添加额外的值以均匀分布
        if i < extra_count:
            expanded_list.append(originallist[i])
    random.shuffle(expanded_list)
    return expanded_list

def expand_list_uniformly_no_shuffle(originallist, target_length):
    """
    将一个原始列表扩展到指定的长度，添加的值均匀地从原始列表中选取。
    原始列表中的值保持不变。

    :param originallist: 初始列表，可以是任意长度
    :param target_length: 目标长度，扩展后的列表长度
    :return: 扩展后的列表
    """
    original_length = len(originallist)
    if original_length == 0:
        raise ValueError("原始列表不能为空")
    if target_length < original_length:
        raise ValueError("目标长度不能小于原始列表的长度")

    # 计算需要添加的元素总数
    total_to_add = target_length - original_length

    # 计算每个元素需要添加的次数
    repeat_count = total_to_add // original_length
    extra_count = total_to_add % original_length

    # 创建新列表，首先包含原始列表的所有元素
    expanded_list = originallist.copy()

    # 添加均匀分布的元素
    for i in range(original_length):
        # 添加重复的值
        expanded_list.extend([originallist[i]] * repeat_count)
        # 如果需要，添加额外的值以均匀分布
        if i < extra_count:
            expanded_list.append(originallist[i])
    return expanded_list

def generate_wind_speed(n):
    """生成风速（m/s），范围[0.0, 7.9]，步长0.1"""
    return [round(random.uniform(0.0, 7.9), 1) for _ in range(n)]


def generate_temperature(n):
    """生成温度（℃），范围[0, 35]整数，优先满足带电水冲洗限制"""
    return [random.randint(0, 35) for _ in range(n)]


def generate_humidity(n):
    """生成相对湿度（%），范围[0, 80]整数"""
    return [random.randint(0, 80) for _ in range(n)]


def generate_precipitation(n, zero_prob=0.7, min_rain=0.1, max_rain=50.0):
    # 生成是否下雨的标志（1表示下雨，0表示无雨）
    rain_flag = np.random.binomial(1, 1 - zero_prob, n)

    # 生成非零降水量（指数分布模拟真实降水）
    # 调整指数分布的scale参数，使得大部分值落在min_rain和max_rain之间
    scale = 5.0
    nonzero_rain = np.random.exponential(scale=scale, size=n)

    # 确保非零降水量在min_rain和max_rain之间
    nonzero_rain = np.clip(nonzero_rain, min_rain, max_rain)

    # 合并结果
    precipitation = np.where(rain_flag, nonzero_rain, 0.0)

    # 保留1位小数并转为列表
    return [float(round(x, 1)) for x in precipitation]


if __name__ == '__main__':
    file_path = "./data/pickle/基建.pickle"
    load_pickle_data(file_path, "基建")
    file_path = "./data/pickle/生产.pickle"
    load_pickle_data(file_path, "生产", num=15000)
    file_path = "./data/pickle/营销.pickle"
    load_pickle_data(file_path, "营销")
